/**
## 这是一个官方通用NFT标准合约接口
如果你想部署一个通用的NFT合约，就应该实现这个接口定义的规则

## `NFT` 资源
表示智能合约中NFT的核心资源类型

## `Collection` 资源
存储用户NFT集合的资源。
它包括一些允许所有者轻松地将令牌移入和移出集合功能。

## `Provider` and `Receiver` 资源接口
提供者和接收者接口遵循特定的命名和行为标准，声明了一些前置和后置条件函数。
通过实现这些接口，仅公开一个或多个字段中的字段和函数的集合，使用户能够共享引用，给用户提供了用令牌执行各种操作、定制资源的能力。

智能合约通过使用资源和接口，以点对点的方式发送和接收代币，而无需与中央分类账交互。
用户要向另一个用户发送NFT，只需提取自己的NFT，然后在接收者的帐户上调用存款功能即可完成传输。

*/


//主NFT合约接口。其他NFT合约可以导入并实现此接口

pub contract interface NonFungibleToken {

    // 此类型的token总数
    pub var totalSupply: UInt64

    // 初始化NFT合约时发出的事件
    pub event ContractInitialized()

	//提取token时发出的事件，
	//表示从中提取的集合的所有者。
	//如果集合不在帐户的存储中，“from”将为“nil”。

    pub event Withdraw(id: UInt64, from: Address?)


	//将token存放到集合时发出的事件。
	//它表示它存放到的集合的所有者。
    pub event Deposit(id: UInt64, to: Address?)

    // NFT资源接口
    pub resource interface INFT {
        // 每个NFT拥有的唯一id
        pub let id: UInt64
    }

    // 实现符合上面NFT资源接口定义的NFT资源
    pub resource NFT: INFT {
        pub let id: UInt64
    }

    // 从集合中提取NFT的接口
    //
    pub resource interface Provider {
        // 从集合中删除NFT并将其移动到调用方
        pub fun withdraw(withdrawID: UInt64): @NFT {
            post {
                result.id == withdrawID: "The ID of the withdrawn token must be the same as the requested ID"
            }
        }
    }

    // 存储NFT到集合的接口
    pub resource interface Receiver {

        // 将NFT作为参数并将其添加到集合中
        pub fun deposit(token: @NFT)
    }

    // 集合中暴露出的公共接口
    pub resource interface CollectionPublic {
		//存储NFT
        pub fun deposit(token: @NFT)
		//返回集合中的ID数组
        pub fun getIDs(): [UInt64]
		//读取指定NFT的信息
        pub fun borrowNFT(id: UInt64): &NFT
    }

	//在执行合同中声明对具体资源类型的需求
    pub resource Collection: Provider, Receiver, CollectionPublic {

        // 用于在集合中保存NFT的词典
        pub var ownedNFTs: @{UInt64: NFT}

        // 从集合中删除NFT并将其移动到调用方
        pub fun withdraw(withdrawID: UInt64): @NFT

		//存储NFT：接受NFT并将其添加到集合词典中，同时将ID添加到ID数组中
        pub fun deposit(token: @NFT)

        // getIDs返回集合中的ID数组
        pub fun getIDs(): [UInt64]

		//返回对集合中NFT的引用
		//以便调用者可以读取数据并从中调用方法
        pub fun borrowNFT(id: UInt64): &NFT {
            pre {
                self.ownedNFTs[id] != nil: "NFT does not exist in the collection!"
            }
        }
    }

	//创建一个空集合，并将其返回给调用者，以便他们可以拥有NFT
    pub fun createEmptyCollection(): @Collection {
        post {
            result.getIDs().length == 0: "The created collection must be empty!"
        }
    }
}
